package com.ease.util {
   import flash.events.Event;
   import flash.events.IEventDispatcher;

   import mx.core.FlexGlobals;
   import mx.core.UIComponent;
   import mx.managers.CursorManager;

   /**
    * Manages busy cursor setting and removal.
    * The main reason to use this class is to provide a quick feedback on user actions, thus
    * enhancing the perception of responsiveness.
    *
    * <p>The typical usage is to call <code>setBusyCursor</code> when a user operation
    * starts. This method sets the busy cursor until the display becomes stable.
    * The display is considered stable when no component is added or layout operation is
    * pending for a predefined interval of time.
    */
   public class BusyCursorManager {
      // The singleton instance.
      private static var _instance:BusyCursorManager;

      private var _enabled:Boolean;
      private var _isBusy:Boolean;

      /**
       * @private Constructor. As a singleton, this class constructor prevents
       * instantiation from other classes. Use BusyCursorManager.instance()
       * to work with the singleton from other classes.
       *
       * @throws Error if the constructor is called by an external class or if
       *    the singelton has already been instantiated.
       */
      public function BusyCursorManager(token:Class) {
         if (token != PrivateConstructorToken) {
            throw new Error("BusyCursorManager cannot be instantiated directly.");
         }
      }

      /**
       * Retrieves the singleton instance of BusyCursorManager.
       */
      public static function get instance():BusyCursorManager {
         if (_instance == null) {
            _instance = new BusyCursorManager(PrivateConstructorToken);
         }
         return _instance;
      }

      /**
       * Indicates whether busy cursor functionality is enabled.
       */
      public function get enabled():Boolean {
         return _enabled;
      }

      /** @private */
      public function set enabled(value:Boolean):void {
         _enabled = true;
      }

      /**
       * Sets the busy cursor, and starts monitoring the display for stability.
       * If the cursor is already busy, then nothing happens.
       *
       * @param autoRemove
       *    Whether to automatically remove the busy cursor when the display becomes stable.
       *    If false, then the caller should also call <code>removeBusyCursor</code>.
       *
       */
      public function setBusyCursor(autoRemove:Boolean = true):void {
         if (!_enabled || _isBusy) {
            return;
         }
         CursorManager.setBusyCursor();
         if (autoRemove) {
            var sysMgr:IEventDispatcher = this.systemManager;
            sysMgr.addEventListener(Event.ADDED, onComponentAddedToDisplay);
         }
         _isBusy = true;
      }

      /**
       * Removes the busy cursor, and aborts display monitoring if necessary.
       * You don't need to call this method if <code>setBusyCursor</code> has been called
       * with <code>autoRemove</code> true.
       */
      public function removeBusyCursor():void {
         if (!_isBusy) {
            return;
         }
         CursorManager.removeBusyCursor();
         _isBusy = false;
      }

      /**
       * The <code>Event.ADDED</code> event handler, invoked when a component
       * is added to the display.
       */
      private function onComponentAddedToDisplay(event:Event):void {
         var sysMgr:IEventDispatcher = this.systemManager;
         sysMgr.removeEventListener(Event.ADDED, onComponentAddedToDisplay);

         RenderingTracker.instance.track(onRenderingCompleted);
      }

      private function onRenderingCompleted(callContext:Object):void {
         removeBusyCursor();
      }

      private function get systemManager():IEventDispatcher {
         return UIComponent(FlexGlobals.topLevelApplication).systemManager;
      }

   }
}

class PrivateConstructorToken {
}